package com.fanghuaiming.test.netty.c5.pipeline;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.nio.charset.Charset;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/****
 * @description:
 * @version:1.0.0
 * @author fanghuaiming
 * @data Created in 2021/9/29 下午9:22
 *
 */
@Slf4j
public class TetsPipelineServer {

  public static void main(String[] args) {
      new ServerBootstrap()
              .group(new NioEventLoopGroup())
              .channel(NioServerSocketChannel.class)
              .childHandler(new ChannelInitializer<NioSocketChannel>() {
                  @Override
                  protected void initChannel(NioSocketChannel ch) throws Exception {
                    // head -> h1 -> h2 -> h3 -> tail
                      ChannelPipeline pipeline = ch.pipeline();
                      //通过 channel 拿到 pipeline
                      pipeline.addLast("h1",new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            log.info("h1");
                            //将数据加工成string
                            ByteBuf buf = (ByteBuf) msg;
                            String name = buf.toString(Charset.defaultCharset());
                            //传递给下一个Handler
                            super.channelRead(ctx, name);
                        }
                    });
                      pipeline.addLast("h2",new ChannelInboundHandlerAdapter(){
                          @Override
                          public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                              log.info("h2");
                              //加工成student
                              Student student = new Student(msg.toString());
                              //将student传递给下一个handler
                              //super.channelRead(ctx, student);
                              //也可以使用channelRead源代码中 ctx.fireChannelRead 将数据传给下一个handler
                              ctx.fireChannelRead(student);
                          }
                      });
                      pipeline.addLast("h4",new ChannelOutboundHandlerAdapter(){
                          @Override
                          public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
                                  throws Exception {
                              log.info("h4");
                              super.write(ctx, msg, promise);
                          }
                      });
                      pipeline.addLast("h3",new ChannelInboundHandlerAdapter(){
                          @Override
                          public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                              log.info("h3");
                              log.info("h3的结果{},class:{}",msg,msg.toString());
                              //因为我们现在这个代码中后面是没有入站handler了,所以可以不用再调用channelRead进行传递了
                              //super.channelRead(ctx, msg);
                              //通过 NioSocketChannel 写数据是出站 消息是 tail -> OutboundHandler6 -> OutboundHandler5 -> OutboundHandler4
                              ch.writeAndFlush(ctx.alloc().buffer().writeBytes("server".getBytes()));

                              //通过 ChannelHandlerContext 写数据是从 InboundHandler3(当前) -> OutboundHandler6
                              //ctx.writeAndFlush(ctx.alloc().buffer().writeBytes("server".getBytes()));
                          }
                      });
                      pipeline.addLast("h5",new ChannelOutboundHandlerAdapter(){
                          @Override
                          public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
                                  throws Exception {
                              log.info("h5");
                              super.write(ctx, msg, promise);
                          }
                      });
                      pipeline.addLast("h6",new ChannelOutboundHandlerAdapter(){
                          @Override
                          public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
                                  throws Exception {
                              log.info("h6");
                              super.write(ctx, msg, promise);
                          }
                      });
                  }
              })
              .bind(8080);
  }

  @Data
  @AllArgsConstructor
  static class  Student {
      String name;
  }
}
